import sys
import os
import shelve
import re
import traceback
import subprocess

import mmc
import frtUI

# This will only be needed in linux so probably just 'vlc'
#vlcRunLine = "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
vlcRunLine = "vlc"
mplayerRunLine = 'mplayer'

class Episode:
	def __init__(self, number, filePath):
		self._episodeNumber = number
		self._filePath = filePath
		self._runCommand = None
		
		# Only relavent for linux
		if filePath.endswith('.avi'): self._runCommand = vlcRunLine

	def get_number(self):
		return self._episodeNumber
	
	def get_file_path(self):
		return self._filePath
	
	def update_path(self, path):
		self._filePath = path
		
	def play(self):
		if os.name == 'nt':
		#if False:
			# This function behaves like you double click the file in explorer
			os.startfile(self._filePath)
		else:
			os.spawnl(os.P_NOWAIT, self._runCommand, '-v', '"'+self._filePath+'"')

class Season:
	def __init__(self, seasonNumber):
		self._seasonNumber = seasonNumber
		self._episodes = {}
		
	def print_(self):
		print "Season ", self._seasonNumber
		for episodeKey in sorted(self._episodes.keys()):
			print "Episode ", self._episodes[episodeKey].get_number(), self._episodes[episodeKey].get_file_path()
	
	def get_episodes(self):
		return self._episodes
			
	def play(self, episode):
		self._episodes[episode].play()
		
	def add_episode(self, episodeNumber, filePath):
		try:
			self._episodes[episodeNumber].update_path(filePath)
		except KeyError:
			self._episodes[episodeNumber] = Episode(episodeNumber, filePath)
			
	def get_episodes(self):
		return self._episodes
		
currSeason = 0
currEpisode = 1

class EpisodeDoesntExist(Exception):
	def __init__(self, show, season, episode):
		print show, "Season", str(season), "Episode", str(episode), "doesn't exist!"

class Show:
	def __init__(self, name):
		self._name = name
		self._seasons = {}
		self._currSeason = -1
		self._currEpisode = -1
		
	def print_(self):
		print "Show: ", self._name
		[self._seasons[season].print_() for season in sorted(self._seasons.keys())]
		
	def get_seasons(self):
		return self._seasons
		
	def add_episode(self, seasonNumber, episodeNumber, filePath):
		try:
			self._seasons[seasonNumber].add_episode(episodeNumber, filePath)
		except KeyError:
			self._seasons[seasonNumber] = Season(seasonNumber)
			self.add_episode(seasonNumber, episodeNumber, filePath)
			
	def set_position(self, season, episode):
		try: 
			self._seasons[int(season)].get_episodes()[int(episode)]
		except KeyError:
			raise EpisodeDoesntExist(self.name, season, episode)
		else:
			self._currSeason = int(season)
			self._currEpisode = int(episode)
	
	def play(self):
		self._seasons[self._currSeason].play(self._currEpisode)

class FRTError(Exception):
	pass

class FRT:
	
	alternateNameShows = {
		'House':'house md',
		'Terminator The Sarah Connor Chronicles':'ttscc|terminator',
		'The Big Bang Theory':'big bang theory|tbbt'
	}
	
	fileName = mmc.fileName 
	#fileName = osp.join(wx.StandardPaths.Get().GetUserConfigDir(),'.mc.data')
		
	def __init__(self, UI):
		self._UI = UI
		
		print self.fileName
		try:
			db = shelve.open(self.fileName)
		except Exception, e:
			print "File " % self.fileName % "failed to open" % e
			if os.path.exists(self.fileName): 
				os.remove(self.fileName)
				self.__init__()
			return
		
		#db = {}
		# load variables
		try:
			self._shows = db['shows']
		except KeyError:
			self._shows = db['shows'] = {}
			
		#files = self.directory_scan('.\\test\\House')
		#self.set_show_position('House', 1, 5)
		#self.play_show('House')
		
	def print_(self):
		[self._shows[show].print_() for show in sorted(self._shows.keys())]
		
	def get_shows(self):
		return self._shows
	
	def set_show_position(self, show, season, episode):
		self._shows[show].set_position(season, episode)
		
	def play_show(self, show):
		self._shows[show].play()	
		
	def directory_scan(self, dir):
		files = []
		extensions = ['.mp4','.avi','.mpg','.divx','.mkv','.wmv']
		for (r,d,f) in os.walk(dir):
			# don't scan hidden dirs,(note to self) is there a way we can get it to ask windows if a dir is hidden? - It'd be a stat type command, no?
			[d.remove(a) for a in d if a.startswith('.')]
			files += [os.path.join(r,a) for a in f if os.path.splitext(a)[1].lower() in extensions]
		
		self.parse_files(files)
		self.print_()
		self.set_db_entry('shows', self._shows)
		self._UI.shows_changed()
		
	def parse_files(self, files):
		'''
			Given a filename, return a tuple containing
			its season and episode number. Returns
			(None,None) if could not be determined
		'''
		for file in files:
			m = \
				re.search(r"([\w\._\s]+)[\s\._][sS]0?(\d?\d)[eE]0?(\d?\d)",file) or \
				re.search(r"([\w\._\s]+)[\s\._]0?(\d?\d)[xX]0?(\d?\d)",file) or \
				re.search(r"([\w\._\s]+)[\s\._](\d)0?(\d?\d)",file) or \
				re.search(r"([\w\._\s]+)[\s\._]0?(\d?\d).*?0?(\d?\d)",file)
			
			if m: self.parse_episode(file,*m.groups())
			else: print "couldn't find show" % file
			
		self.set_db_entry('shows', self._shows)
			
	def parse_episode(self, file, show, season, episode):
		show = show.strip('. ')
		show = show.replace('.', ' ')
		show = show.replace('_', ' ')
		
		for k,v in self.alternateNameShows.iteritems():
			m = re.search(re.compile(v,re.IGNORECASE),show)
			if m: show = k
				
		show = show.title()
		
		# if file relative ie: .\relative\path\to\file add the base onto the start
		# or should it be relative?
		if file.startswith('.'): file = os.path.dirname(__file__) + file.lstrip('.')
		try:
			self._shows[show].add_episode(int(season), int(episode), file)
		except KeyError:
			self.create_new_show(show)
			self.parse_episode(file, show, season, episode)
		
	def create_new_show(self, show):
		self._shows[show] = Show(show)
		
	def set_db_entry(self, entry, value):
		try:
			db = shelve.open(self.fileName)
		except Exception, e:
			print "Failed to open database!" % e
			raise MCError("Failed to open database" % e)
		db[entry] = value
		db.close()
		
	def get_db_entry(self, entry):
		try:
			db = shelve.open(self.fileName)
		except Exception, e:
			print "Failed to open database!" % e
			raise MCError("Failed to open database" % e)
		value = db[entry]
		db.close()
		
		return value